#ifndef __TDP2_GUARD_HPP__
#define __TDP2_GUARD_HPP__

#include "tdp2.hpp"
#include "tdp2_allocator.hpp"

namespace TDP
{
	namespace Containers
	{
		template<class _T>
		class SingleInstance
		{
		private:
			RDX::ObjectManagement::Allocator _alloc;
			_T *_instance;

		public:
			explicit SingleInstance(const RDX::ObjectManagement::Allocator &alloc);
			~SingleInstance();

			const RDX::ObjectManagement::Allocator &GetAllocator() const;
			void SetInstance(_T *instance);
			_T *Instance();
			const _T *Instance() const;
		};
	};
};

#include "tdp2_error.hpp"

namespace TDP
{
	namespace Containers
	{
		template<class _T>
		SingleInstance<_T>::SingleInstance(const RDX::ObjectManagement::Allocator &alloc)
		{
			_alloc = alloc;
			_instance = NULL;
		}

		template<class _T>
		SingleInstance<_T>::~SingleInstance()
		{
			SetInstance(NULL);
		}
		
		template<class _T>
		const RDX::ObjectManagement::Allocator &SingleInstance<_T>::GetAllocator() const
		{
			return _alloc;
		}
		
		template<class _T>
		void SingleInstance<_T>::SetInstance(_T *instance)
		{
			if(_instance != NULL)
			{
				_instance->~_T();
				_alloc.Realloc(_instance, 0);
			}

			_instance = instance;
		}

		template<class _T>
		const _T *SingleInstance<_T>::Instance() const
		{
			return _instance;
		}

		template<class _T>
		_T *SingleInstance<_T>::Instance()
		{
			return _instance;
		}
	};
};

#define TDP_SI_CREATE(si, ph, t, params)	\
	do\
	{\
		t *macroCreatedInstance = (si).GetAllocator().Realloc<t>(NULL, 1);\
		if(macroCreatedInstance == NULL)\
			TDP::Panic((ph), FatalErrors::ERR_AllocationFailed);\
		try\
		{\
			new (macroCreatedInstance) t params;\
		}\
		catch(...)\
		{\
			(si).GetAllocator().Realloc(macroCreatedInstance, 0);\
			throw;\
		}\
		(si).SetInstance(macroCreatedInstance);\
	} while(0)

#endif
